package ru.ifmo.cppsc.translator.generated;

import ru.ifmo.cppsc.syntactic.TreeNode;
import ru.ifmo.cppsc.translator.TreeNodeProcessor;
import ru.ifmo.cppsc.translator.TableRecord;
import ru.ifmo.cppsc.translator.SymbolTable;
import ru.ifmo.cppsc.grammar.Production;

import java.util.HashMap;

abstract class ProcessorBase implements TreeNodeProcessor {
    public void ProcessTreeNode (TreeNode node) {
        for ( TreeNode child : node.getChildren()) {
            CodeContainer.executeCode(child);
        }
        doProcess(node);
    }

    public abstract void doProcess(TreeNode node);
}

public class CodeContainer {

    private static HashMap<String, TreeNodeProcessor> prodMap;

    public static final String ERROR_TYPE = "errorType";
    public static final String TYPE_OK = "TypeOK";
    public static SymbolTable table;

    public static void executeCode(TreeNode node) {
        Production p = node.getProduction();
        if (p != null) {
            prodMap.get(p.toString()).ProcessTreeNode(node);
        }    
    }

    public static void generateMap () {
        prodMap = new HashMap<String, TreeNodeProcessor>();
        prodMap.put("Root StatementList", new TreeNodeProcessor0());
        prodMap.put("StatementList Statement StatementList", new TreeNodeProcessor1());
        prodMap.put("StatementList Statement", new TreeNodeProcessor2());
        prodMap.put("Statement CommaExpression ;", new TreeNodeProcessor3());
        prodMap.put("Statement VarDefStatement ;", new TreeNodeProcessor4());
        prodMap.put("VarDefStatement vardef", new TreeNodeProcessor5());
        prodMap.put("PrimaryExpression id", new TreeNodeProcessor6());
        prodMap.put("PrimaryExpression ParenExpression", new TreeNodeProcessor7());
        prodMap.put("ParenExpression ( CommaExpression1 )", new TreeNodeProcessor8());
        prodMap.put("PostfixExpression PrimaryExpression", new TreeNodeProcessor9());
        prodMap.put("PostfixExpression PostfixExpression ParenExpression", new TreeNodeProcessor10());
        prodMap.put("MultiplicativeExpression PostfixExpression", new TreeNodeProcessor11());
        prodMap.put("MultiplicativeExpression MultiplicativeExpression * PostfixExpression", new TreeNodeProcessor12());
        prodMap.put("MultiplicativeExpression MultiplicativeExpression / PostfixExpression", new TreeNodeProcessor13());
        prodMap.put("MultiplicativeExpression MultiplicativeExpression % PostfixExpression", new TreeNodeProcessor14());
        prodMap.put("AdditiveExpression MultiplicativeExpression", new TreeNodeProcessor15());
        prodMap.put("AdditiveExpression AdditiveExpression + MultiplicativeExpression", new TreeNodeProcessor16());
        prodMap.put("AdditiveExpression AdditiveExpression - MultiplicativeExpression", new TreeNodeProcessor17());
        prodMap.put("RelationalExpression AdditiveExpression", new TreeNodeProcessor18());
        prodMap.put("RelationalExpression RelationalExpression < AdditiveExpression", new TreeNodeProcessor19());
        prodMap.put("RelationalExpression RelationalExpression > AdditiveExpression", new TreeNodeProcessor20());
        prodMap.put("EqualityExpression RelationalExpression", new TreeNodeProcessor21());
        prodMap.put("EqualityExpression EqualityExpression == RelationalExpression", new TreeNodeProcessor22());
        prodMap.put("EqualityExpression EqualityExpression != RelationalExpression", new TreeNodeProcessor23());
        prodMap.put("LogicalAndExpression EqualityExpression", new TreeNodeProcessor24());
        prodMap.put("LogicalAndExpression LogicalAndExpression && EqualityExpression", new TreeNodeProcessor25());
        prodMap.put("LogicalOrExpression LogicalAndExpression", new TreeNodeProcessor26());
        prodMap.put("LogicalOrExpression LogicalOrExpression || LogicalAndExpression", new TreeNodeProcessor27());
        prodMap.put("ConditionalExpression LogicalOrExpression", new TreeNodeProcessor28());
        prodMap.put("AssignmentExpression ConditionalExpression", new TreeNodeProcessor29());
        prodMap.put("AssignmentExpression PostfixExpression = AssignmentExpression", new TreeNodeProcessor30());
        prodMap.put("CommaExpression AssignmentExpression", new TreeNodeProcessor31());
        prodMap.put("CommaExpression CommaExpression , AssignmentExpression", new TreeNodeProcessor32());
        prodMap.put("CommaExpression1 CommaExpression", new TreeNodeProcessor33());
        prodMap.put("StatementList Statement", new TreeNodeProcessor34());

    }
}

// Root StatementList
class TreeNodeProcessor0 extends ProcessorBase {
    public void doProcess(TreeNode node) {
if (!node.getChild(0).getType().equals(CodeContainer.ERROR_TYPE)) {
  node.setType(CodeContainer.TYPE_OK);
}
}
}

// StatementList Statement StatementList
class TreeNodeProcessor1 extends ProcessorBase {
    public void doProcess(TreeNode node) {
if (!node.getChild(0).getType().equals(CodeContainer.ERROR_TYPE) && !node.getChild(1).getType().equals(CodeContainer.ERROR_TYPE)) {
  node.setType(CodeContainer.TYPE_OK);
}
}
}

// StatementList Statement
class TreeNodeProcessor2 extends ProcessorBase {
    public void doProcess(TreeNode node) {
if (!node.getChild(0).getType().equals(CodeContainer.ERROR_TYPE)) {
  node.setType(CodeContainer.TYPE_OK);
}
}
}

// Statement CommaExpression ;
class TreeNodeProcessor3 extends ProcessorBase {
    public void doProcess(TreeNode node) {
if (!node.getChild(0).getType().equals(CodeContainer.ERROR_TYPE)) {
  node.setType(CodeContainer.TYPE_OK);
}
}
}

// Statement VarDefStatement ;
class TreeNodeProcessor4 extends ProcessorBase {
    public void doProcess(TreeNode node) {
if (!node.getChild(0).getType().equals(CodeContainer.ERROR_TYPE)) {
  node.setType(CodeContainer.TYPE_OK);
}
}
}

// VarDefStatement vardef
class TreeNodeProcessor5 extends ProcessorBase {
    public void doProcess(TreeNode node) {
if (!node.getChild(0).getType().equals(CodeContainer.ERROR_TYPE)) {
  node.setType(CodeContainer.TYPE_OK);
}
}
}

// PrimaryExpression id
class TreeNodeProcessor6 extends ProcessorBase {
    public void doProcess(TreeNode node) {
node.setType(node.getChild(0).getType());
}
}

// PrimaryExpression ParenExpression
class TreeNodeProcessor7 extends ProcessorBase {
    public void doProcess(TreeNode node) {
node.setType(node.getChild(0).getType());
}
}

// ParenExpression ( CommaExpression1 )
class TreeNodeProcessor8 extends ProcessorBase {
    public void doProcess(TreeNode node) {
node.setType(node.getChild(1).getType());
}
}

// PostfixExpression PrimaryExpression
class TreeNodeProcessor9 extends ProcessorBase {
    public void doProcess(TreeNode node) {
node.setType(node.getChild(0).getType());
}
}

// PostfixExpression PostfixExpression ParenExpression
class TreeNodeProcessor10 extends ProcessorBase {
    public void doProcess(TreeNode node) {
node.setType(node.getChild(0).getType());
}
}

// MultiplicativeExpression PostfixExpression
class TreeNodeProcessor11 extends ProcessorBase {
    public void doProcess(TreeNode node) {
node.setType(node.getChild(0).getType());
}
}

// MultiplicativeExpression MultiplicativeExpression * PostfixExpression
class TreeNodeProcessor12 extends ProcessorBase {
    public void doProcess(TreeNode node) {
if (!node.getChild(0).getType().equals(node.getChild(2).getType())) {
  node.setType(CodeContainer.ERROR_TYPE);
} else {
  node.setType(node.getChild(0).getType());
}
}
}

// MultiplicativeExpression MultiplicativeExpression / PostfixExpression
class TreeNodeProcessor13 extends ProcessorBase {
    public void doProcess(TreeNode node) {
if (!node.getChild(0).getType().equals(node.getChild(2).getType())) {
  node.setType(CodeContainer.ERROR_TYPE);
} else {
  node.setType(node.getChild(0).getType());
}
}
}

// MultiplicativeExpression MultiplicativeExpression % PostfixExpression
class TreeNodeProcessor14 extends ProcessorBase {
    public void doProcess(TreeNode node) {
if (!node.getChild(0).getType().equals(node.getChild(2).getType())) {
  node.setType(CodeContainer.ERROR_TYPE);
} else 
if (!node.getChild(0).getType().equals("int")) {
  node.setType(CodeContainer.ERROR_TYPE);
} else {
  node.setType(node.getChild(0).getType());
}
}
}

// AdditiveExpression MultiplicativeExpression
class TreeNodeProcessor15 extends ProcessorBase {
    public void doProcess(TreeNode node) {
node.setType(node.getChild(0).getType());
}
}

// AdditiveExpression AdditiveExpression + MultiplicativeExpression
class TreeNodeProcessor16 extends ProcessorBase {
    public void doProcess(TreeNode node) {
if (!node.getChild(0).getType().equals(node.getChild(2).getType())) {
  node.setType(CodeContainer.ERROR_TYPE);
} else {
  node.setType(node.getChild(0).getType());
}
}
}

// AdditiveExpression AdditiveExpression - MultiplicativeExpression
class TreeNodeProcessor17 extends ProcessorBase {
    public void doProcess(TreeNode node) {
if (!node.getChild(0).getType().equals(node.getChild(2).getType())) {
  node.setType(CodeContainer.ERROR_TYPE);
} else {
  node.setType(node.getChild(0).getType());
}
}
}

// RelationalExpression AdditiveExpression
class TreeNodeProcessor18 extends ProcessorBase {
    public void doProcess(TreeNode node) {
node.setType(node.getChild(0).getType());
}
}

// RelationalExpression RelationalExpression < AdditiveExpression
class TreeNodeProcessor19 extends ProcessorBase {
    public void doProcess(TreeNode node) {
if (!node.getChild(0).getType().equals(node.getChild(2).getType())) {
  node.setType(CodeContainer.ERROR_TYPE);
} else {
  node.setType("bool");
}
}
}

// RelationalExpression RelationalExpression > AdditiveExpression
class TreeNodeProcessor20 extends ProcessorBase {
    public void doProcess(TreeNode node) {
if (!node.getChild(0).getType().equals(node.getChild(2).getType())) {
  node.setType(CodeContainer.ERROR_TYPE);
} else {
  node.setType("bool");
}
}
}

// EqualityExpression RelationalExpression
class TreeNodeProcessor21 extends ProcessorBase {
    public void doProcess(TreeNode node) {
node.setType(node.getChild(0).getType());
}
}

// EqualityExpression EqualityExpression == RelationalExpression
class TreeNodeProcessor22 extends ProcessorBase {
    public void doProcess(TreeNode node) {
if (!node.getChild(0).getType().equals(node.getChild(2).getType())) {
  node.setType(CodeContainer.ERROR_TYPE);
} else {
  node.setType("bool");
}
}
}

// EqualityExpression EqualityExpression != RelationalExpression
class TreeNodeProcessor23 extends ProcessorBase {
    public void doProcess(TreeNode node) {
if (!node.getChild(0).getType().equals(node.getChild(2).getType())) {
  node.setType(CodeContainer.ERROR_TYPE);
} else {
  node.setType(node.getChild(0).getType());
}
}
}

// LogicalAndExpression EqualityExpression
class TreeNodeProcessor24 extends ProcessorBase {
    public void doProcess(TreeNode node) {
node.setType(node.getChild(0).getType());
}
}

// LogicalAndExpression LogicalAndExpression && EqualityExpression
class TreeNodeProcessor25 extends ProcessorBase {
    public void doProcess(TreeNode node) {
if (!node.getChild(0).getType().equals(node.getChild(2).getType())) {
  node.setType(CodeContainer.ERROR_TYPE);
} else {
  node.setType(node.getChild(0).getType());
}
}
}

// LogicalOrExpression LogicalAndExpression
class TreeNodeProcessor26 extends ProcessorBase {
    public void doProcess(TreeNode node) {
node.setType(node.getChild(0).getType());
}
}

// LogicalOrExpression LogicalOrExpression || LogicalAndExpression
class TreeNodeProcessor27 extends ProcessorBase {
    public void doProcess(TreeNode node) {
if (!node.getChild(0).getType().equals(node.getChild(2).getType())) {
  node.setType(CodeContainer.ERROR_TYPE);
} else {
  node.setType(node.getChild(0).getType());
}
}
}

// ConditionalExpression LogicalOrExpression
class TreeNodeProcessor28 extends ProcessorBase {
    public void doProcess(TreeNode node) {
node.setType(node.getChild(0).getType());
}
}

// AssignmentExpression ConditionalExpression
class TreeNodeProcessor29 extends ProcessorBase {
    public void doProcess(TreeNode node) {
node.setType(node.getChild(0).getType());
}
}

// AssignmentExpression PostfixExpression = AssignmentExpression
class TreeNodeProcessor30 extends ProcessorBase {
    public void doProcess(TreeNode node) {
if (!node.getChild(0).getType().equals(node.getChild(2).getType())) {
  node.setType(CodeContainer.ERROR_TYPE);
} else {
  node.setType(node.getChild(0).getType());
}
}
}

// CommaExpression AssignmentExpression
class TreeNodeProcessor31 extends ProcessorBase {
    public void doProcess(TreeNode node) {
node.setType(node.getChild(0).getType());
}
}

// CommaExpression CommaExpression , AssignmentExpression
class TreeNodeProcessor32 extends ProcessorBase {
    public void doProcess(TreeNode node) {
System.out.println("Argument list are not supported yet!");
}
}

// CommaExpression1 CommaExpression
class TreeNodeProcessor33 extends ProcessorBase {
    public void doProcess(TreeNode node) {
node.setType(node.getChild(0).getType());
}
}

// StatementList Statement
class TreeNodeProcessor34 extends ProcessorBase {
    public void doProcess(TreeNode node) {
if (!node.getChild(0).getType().equals(CodeContainer.ERROR_TYPE)) {
  node.setType(CodeContainer.TYPE_OK);
}
}
}

